package com.example.drainage.ui.shadow

import android.graphics.*
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import androidx.core.graphics.toRectF

/**
 * 一般用法:View.setShadow {
 *      shadowAffectRadius = 15.dpInt   // 模糊半径
 *      shadowColor = Color.BLUE        // 阴影颜色
 *      shapeCornerRadius = 5.dpInt     // 背景圆角,可以不设置
 *      shapeSolidColor = Color.YELLOW  // 如果不设置,则颜色跟shadowColor一致
 * }
 *
 * [ShadowSetting.shadowMargin]:留给阴影显示的空间大小
 * [ShadowSetting.shadowAffectRadius]:模糊半径
 *
 * [ShadowSetting.shadowMargin]与[ShadowSetting.shadowAffectRadius]一般都是相等的,阴影占完所有Margin空间
 * 不设置[ShadowSetting.shadowAffectRadius]时,自动获取[ShadowSetting.shadowMargin]的最大值作为阴影影响范围
 * 有的情况需要特殊处理:
 *  比如View贴边在屏幕右侧,那么右边[ShadowSetting.shadowMarginRight]应该是0;
 *  比如说含有[ShadowSetting.shadowDx]时,右侧需要更多的距离来展示阴影效果,
 *  那么就需要设定好[ShadowSetting.shadowAffectRadius]和[ShadowSetting.shadowMarginRight]
 *
 * @author 创建人 ：yanghaozhang
 * @version 1.0
 * @package 包名 ：com.example.drainage.ui.shadow
 * @createTime 创建时间 ：2021/11/24
 * @modifyBy 修改人 ：
 * @modifyTime 修改时间 ：
 * @modifyMemo 修改备注：
 */
class ShadowDrawable(setting: ShadowSetting) : Drawable() {

    constructor(settingBlock: ShadowSetting.() -> Unit) : this(ShadowSetting().apply(settingBlock))

    private var shadowSetting: ShadowSetting

    private val shadowPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        style = Paint.Style.FILL
    }

    private val shadowOffsetRect = Rect()

    private val shadowRect = Rect()

    private val shapeCornerRadii: FloatArray = FloatArray(8)

    private var shapeDrawable: GradientDrawable? = null

    private val path = Path()

    init {
        shadowSetting = setting
        init()
    }

    private fun init() {
        initShadow()
        initBackgroundShape()
    }

    private fun initShadow() {
        val setting = shadowSetting
        shadowOffsetRect.apply {
            left = setting.shadowMarginLeft ?: setting.shadowMargin ?: 0
            right = setting.shadowMarginRight ?: setting.shadowMargin ?: 0
            top = setting.shadowMarginTop ?: setting.shadowMargin ?: 0
            bottom = setting.shadowMarginBottom ?: setting.shadowMargin ?: 0
        }

        setting.apply {
            shadowPaint.setShadowLayer(
                shadowAffectRadius,
                shadowDx,
                shadowDy,
                shadowColor ?: Color.WHITE
            )
            // 通过path绘制阴影的圆角会比shape GradientDrawable绘制的要大,所以要统一颜色
            shadowPaint.color = shapeStrokeColor ?: shapeSolidColor ?: shadowColor ?: Color.WHITE
        }
    }

    private fun initBackgroundShape() {
        val setting = shadowSetting
        val radiusTopLeft = setting.shapeCornerRadiusTL ?: setting.shapeCornerRadius ?: 0
        val radiusTopRight = setting.shapeCornerRadiusTR ?: setting.shapeCornerRadius ?: 0
        val radiusBottomLeft = setting.shapeCornerRadiusBL ?: setting.shapeCornerRadius ?: 0
        val radiusBottomRight = setting.shapeCornerRadiusBR ?: setting.shapeCornerRadius ?: 0

        val radii = shapeCornerRadii
        radii[0] = radiusTopLeft.toFloat()
        radii[1] = radiusTopLeft.toFloat()
        radii[2] = radiusTopRight.toFloat()
        radii[3] = radiusTopRight.toFloat()
        radii[4] = radiusBottomRight.toFloat()
        radii[5] = radiusBottomRight.toFloat()
        radii[6] = radiusBottomLeft.toFloat()
        radii[7] = radiusBottomLeft.toFloat()

        shapeDrawable = if (setting.shapeSolidColor == null) {
            null
        } else {
            GradientDrawable().apply {
                setColor(setting.shapeSolidColor!!)
                if ((radiusTopLeft or radiusTopRight or radiusBottomLeft or radiusBottomRight) != 0) {
                    cornerRadii = radii
                }
                if (setting.shapeStrokeColor != null && setting.shapeStrokeWidth != null) {
                    setStroke(setting.shapeStrokeWidth!!, setting.shapeStrokeColor!!)
                }
            }
        }
    }

    override fun draw(canvas: Canvas) {
        resetShadowRect()
        drawShadow(canvas)
        drawBackgroundShapeRect(canvas)
    }

    private fun resetShadowRect() {
        shadowRect.apply {
            left = bounds.left + shadowOffsetRect.left
            top = bounds.top + shadowOffsetRect.top
            right = bounds.right - shadowOffsetRect.right
            bottom = bounds.bottom - shadowOffsetRect.bottom
        }
    }

    private fun drawShadow(canvas: Canvas) {
        path.reset()
        path.addRoundRect(shadowRect.toRectF(), shapeCornerRadii, Path.Direction.CW)
        canvas.drawPath(path, shadowPaint)
    }

    private fun drawBackgroundShapeRect(canvas: Canvas) {
        shapeDrawable?.bounds = shadowRect
        shapeDrawable?.draw(canvas)
    }

    override fun setAlpha(alpha: Int) {

    }

    override fun setColorFilter(colorFilter: ColorFilter?) {

    }

    @Deprecated("Deprecated in Java", ReplaceWith("PixelFormat.TRANSLUCENT", "android.graphics.PixelFormat"))
    override fun getOpacity(): Int {
        // not sure, so be safe
        return PixelFormat.TRANSLUCENT
    }

    //--------------------外部调用方法--------------------------

    fun updateSetting(block: ShadowSetting.() -> Unit): ShadowDrawable {
        val setting = ShadowSetting()
        block.invoke(setting)
        updateSetting(setting)
        return this
    }

    fun updateSetting(setting: ShadowSetting): ShadowDrawable {
        shadowSetting = setting
        init()
        invalidateSelf()
        return this
    }

    fun getShadowSetting(): ShadowSetting {
        return shadowSetting
    }
}